import 'dart:async';
import 'dart:io';

import 'package:electronic_pet/chat_gpt.dart';
import 'package:electronic_pet/other_packages/advanced_features.dart';
import 'package:electronic_pet/pages/ResultView.dart';
import 'package:electronic_pet/pages/desktop_popup/toolbar_item_always_on_top.dart';
import 'package:electronic_pet/services/services.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:screen_capturer/screen_capturer.dart';
import 'package:screen_retriever/screen_retriever.dart';
import 'package:screen_text_extractor/screen_text_extractor.dart';
import 'package:tray_manager/tray_manager.dart';
import 'package:window_manager/window_manager.dart';

import '../../utilities/R.dart';
import '../../utilities/platform_util.dart';
import '../MainInputView.dart';
import 'toolbar_item_settings.dart';

const kMenuItemKeyShow = 'show';
const kMenuItemKeyQuitApp = 'quit-app';
class DesktopPopupPage extends StatefulWidget {
  const DesktopPopupPage({Key? key}) : super(key: key);

  @override
  State<StatefulWidget> createState() => _DesktopPopupPageState();
}

class _DesktopPopupPageState extends State<DesktopPopupPage>
    with
    WidgetsBindingObserver,
    TrayListener,
    WindowListener {
  final GlobalKey _inputViewKey = GlobalKey();
  final GlobalKey _resultsViewKey = GlobalKey();
  final FocusNode _focusNode = FocusNode();
  String _result = '';
  final ScrollController _scrollController = ScrollController();
  final TextEditingController _textEditingController = TextEditingController();
  String _text = '';
  Timer? _resizeTimer;
  Offset _lastShownPosition = Offset.zero;
  bool _isAllowedScreenCaptureAccess = true;
  bool _isAllowedScreenSelectionAccess = true;
  Version? _latestVersion;


  Widget _buildResultsView(BuildContext context) {
    if (_result == "") {
      return const SizedBox.shrink();
    } else {
      return ResultView(
          text: _result,
          controller: _scrollController,
          viewKey: _resultsViewKey);
    }
  }

  void _handleTextChanged(String? newValue) {
    setState(() {
      // 移除前后多余的空格
      _text = (newValue ?? '').trim();
    });
  }

  Widget _buildInputView() {
    return SizedBox(
        key: _inputViewKey,
        width: double.infinity,
        child: Column(mainAxisSize: MainAxisSize.min, children: [
          MainInputView(
            focusNode: _focusNode,
            controller: _textEditingController,
            onButtonTappedClear: _handleButtonTappedClear,
            onButtonTappedTrans: _handleButtonTappedTrans,
            onChanged: (newValue) => _handleTextChanged(newValue),
          ),
        ]));
  }


  @override
  void initState() {
    WidgetsBinding.instance.addObserver(this);
    if (kIsLinux || kIsMacOS || kIsWindows) {
      trayManager.addListener(this);
      windowManager.addListener(this);
      _init();
    }
    _loadData();
    super.initState();
  }

  void _init() async {
    if (kIsMacOS) {
      _isAllowedScreenCaptureAccess =
      await ScreenCapturer.instance.isAccessAllowed();
      _isAllowedScreenSelectionAccess =
      await screenTextExtractor.isAccessAllowed();
    }

    // ShortcutService.instance.start();

    // 初始化托盘图标
    await _initTrayIcon();
    await Future.delayed(const Duration(milliseconds: 100));
    WindowOptions windowOptions = const WindowOptions(
      titleBarStyle: TitleBarStyle.hidden,
      windowButtonVisibility: false,
      skipTaskbar: true,
      backgroundColor: Colors.transparent,
    );
    windowManager.waitUntilReadyToShow(windowOptions, () async {
      if (kIsMacOS) {
        await windowManager.setVisibleOnAllWorkspaces(
          true,
          visibleOnFullScreen: true,
        );
      }
      if (kIsLinux || kIsWindows) {
        Display primaryDisplay = await screenRetriever.getPrimaryDisplay();
        Size windowSize = await windowManager.getSize();
        _lastShownPosition = Offset(
          primaryDisplay.size.width - windowSize.width - 50,
          50,
        );
        await windowManager.setPosition(_lastShownPosition);
      }
      await Future.delayed(const Duration(milliseconds: 100));
      await _windowShow(
        isShowBelowTray: kIsMacOS,
      );
    });
    setState(() {});
  }

  @override
  void onTrayMenuItemClick(MenuItem menuItem) async {
    switch (menuItem.key) {
      case kMenuItemKeyShow:
        await Future.delayed(const Duration(milliseconds: 300));
        await _windowShow();
        break;
      case kMenuItemKeyQuitApp:
        await trayManager.destroy();
        exit(0);
    }
  }

  @override
  void onTrayIconRightMouseDown() {
    trayManager.popUpContextMenu();
  }

  Future<void> _initTrayIcon() async {
    if (kIsWeb) return;

    String trayIconName = platformSelect<String>(
          () => 'tray_icon_black.png',
      windows: () => 'tray_icon_black.ico',
      linux: () => 'tray_icon.ico',
    );

    await trayManager.destroy();
    await trayManager.setIcon(
        R.image(trayIconName),
        isTemplate: kIsMacOS ? true : false,
      );
      await Future.delayed(const Duration(milliseconds: 10));
      Menu menu = Menu(
        items: [
          MenuItem(
            label: '有Bug可加V交流：RuotongYu001',
            disabled: true,
          ),
          MenuItem.separator(),
          MenuItem(
            key: kMenuItemKeyQuitApp,
            label: '退出',
          ),
        ],
      );
      await trayManager.setContextMenu(menu);
    }

  Future<void> _windowShow({
    bool isShowBelowTray = false,
  }) async {
    bool isAlwaysOnTop = await windowManager.isAlwaysOnTop();
    Size windowSize = await windowManager.getSize();

    if (kIsLinux) {
      await windowManager.setPosition(_lastShownPosition);
    }

    if (kIsMacOS && isShowBelowTray) {
      Rect? trayIconBounds = await trayManager.getBounds();
      if (trayIconBounds != null) {
        Size trayIconSize = trayIconBounds.size;
        Offset trayIconPosition = trayIconBounds.topLeft;

        Offset newPosition = Offset(
          trayIconPosition.dx - ((windowSize.width - trayIconSize.width) / 2),
          trayIconPosition.dy,
        );

        if (!isAlwaysOnTop) {
          await windowManager.setPosition(newPosition);
        }
      }
    }

    bool isVisible = await windowManager.isVisible();
    if (!isVisible) {
      await windowManager.show();
    } else {
      await windowManager.focus();
    }

    // Linux 下无法激活窗口临时解决方案
    if (kIsLinux && !isAlwaysOnTop) {
      await windowManager.setAlwaysOnTop(true);
      await Future.delayed(const Duration(milliseconds: 10));
      await windowManager.setAlwaysOnTop(false);
      await Future.delayed(const Duration(milliseconds: 10));
      await windowManager.focus();
    }
  }

  @override
  Widget build(BuildContext context) {
    WidgetsBinding.instance.addPostFrameCallback((_) => _windowResize());
    return Scaffold(
        appBar: _buildAppBar(context),
        body: _buildBody(context)
    );
  }
    PreferredSizeWidget _buildAppBar(BuildContext context) {
    handleDismissed() => setState(() {});

    return PreferredSize(
      preferredSize: const Size.fromHeight(34),
      child: Container(
        padding: const EdgeInsets.only(left: 8, right: 8, top: 0),
        child: Row(
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            const ToolbarItemAlwaysOnTop(),
            Expanded(child: Container()),
            ToolbarItemSettings(
              onSubPageDismissed: handleDismissed,
            ),
          ],
        ),
      ),
    );
  }
  Widget _buildBody(BuildContext context) {
    return SizedBox(
      height: double.infinity,
      child: Column(
        mainAxisSize: MainAxisSize.max,
        children: [
          _buildInputView(),
          _buildResultsView(context),
        ],
      ),
    );
  }

  void _loadData() async {
    try {
      await localDb.setCurrentUser(
        localDb.user,
      );
    } catch (error) {
      // skip
    }
    try {
      _latestVersion = await apiClient.version('latest').get();
      setState(() {});
    } catch (error) {
      // skip
    }
    try {
      await localDb.loadFromCloudServer();
    } catch (error) {
      // skip
    }
  }

  Future<void> _queryData() async {
    _result = await ChatGPT().query(_text);
  }

  @override
  void onWindowMove() async {
    _lastShownPosition = await windowManager.getPosition();
  }

  void _windowResize() {
    if (Navigator.of(context).canPop()) return;

    if (_resizeTimer != null && _resizeTimer!.isActive) {
      _resizeTimer?.cancel();
    }
    _resizeTimer = Timer.periodic(const Duration(milliseconds: 10), (_) async {
      if (!kIsMacOS) {
        await Future.delayed(const Duration(milliseconds: 100));
      }
      RenderBox? rb2 =
          _inputViewKey.currentContext?.findRenderObject() as RenderBox?;
      RenderBox? rb3 =
          _resultsViewKey.currentContext?.findRenderObject() as RenderBox?;

      double toolbarViewHeight = 36.0;
      double inputViewHeight = rb2?.size.height ?? 0;
      double resultsViewHeight = rb3?.size.height ?? 0;
      try {
        double newWindowHeight = toolbarViewHeight +
            inputViewHeight +
            resultsViewHeight +
            (kIsWindows ? 5 : 0);
        Size oldSize = await windowManager.getSize();
        Size newSize = Size(
          oldSize.width,
          newWindowHeight < 800 ? newWindowHeight : 800,
        );
        if (oldSize.width != newSize.width ||
            oldSize.height != newSize.height) {
          await windowManager.setSize(newSize, animate: false);
        }
      } catch (error) {
        // print(error);
      }

      if (_resizeTimer != null) {
        _resizeTimer?.cancel();
        _resizeTimer = null;
      }
    });
  }

  void _handleButtonTappedClear() {
    setState(() {
      _text = "";
      _result = "";
    });
    _textEditingController.clear();
    _focusNode.requestFocus();
  }

  void _handleButtonTappedTrans() async {
    setState(() {
      _result = "等待结果中";
    });
    await _queryData();
    setState(() {});
  }

  @override
  void dispose() {
    _textEditingController.dispose();
    super.dispose();
  }

  @override
  void onWindowFocus() async {
    _focusNode.requestFocus();
  }
}
